using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;


using System.ComponentModel;
using System.Data;
using System.IO;
using System.Windows.Forms;
using System.Threading;

namespace WindowsApplication1
{
  class Ratios
  {   // indeksy niezmiennikow w tablicy zwracanej przez 
      const byte rc1 = 0;
      const byte rc2 = 1;
      const byte rc12 = 2;
      const byte rhar = 3;

      public static Bitmap itest;
      public static Bitmap itest2;

      /*
      static void oblewanie(ref Bitmap org, ref Bitmap tmp, int x, int y, ref int[,] cr)
      {
          tmp.SetPixel(x, y, Color.Red); //pix. jest krawedzia i nalezy do obwodu

          // dla kazdego z 8 sasiadow pix nalezacego do zew. konturu
          for (int k = 0; k < 8; k++)
          {
              // kolor pobierany z tymczasowego obrazu, gdzie na czarno sa zaznaczone granice 
              // obiektu i tla, ale nalezace do obiektu
              string n = tmp.GetPixel(x + cr[k, 0], y + cr[k, 1]).Name;
              if (n == "ff000000" || n == "ff040404")  // jesli czarny, czyli sasiad rowniez jest krawedzia
              {
                  // tutaj kolor pobierany z orginalu
                  // 1. w otoczeniu obecnego czarnego (krawedz/granica) pix. wyszukujemy bialych pix (tlo)
                  // 2. dla kazdego z jego sasiadow sprawdzamy czy w ich otoczeniu sa biale pixele
                  // jesli pix z pkt 1 i 2 to ten sam punkt to znaleziono punkt konturu
                  // oznaczenie go na czerwono na obrazie tymczasowym, przerwanie petli, rekurencja
                  for (int ti = 0; ti < 8; ti++)
                      for (int tj = 0; tj < 8; tj++)
                      {
                          string t7 = org.GetPixel(x + cr[ti, 0], y + cr[ti, 1]).Name;
                          string t8 = org.GetPixel(x + cr[k, 0] + cr[tj, 0], y + cr[k, 1] + cr[tj, 1]).Name;
                          if ( (t7 == "ffffffff" || t7 == "fffcfcfc") &&
                               (t8 == "ffffffff" || t8 == "fffcfcfc") &&
                              (cr[ti, 0] == cr[k, 0] + cr[tj, 0]) &&
                              (cr[ti, 1] == cr[k, 1] + cr[tj, 1]))
                          {
                              oblewanie(ref org, ref tmp, x + cr[k, 0], y + cr[k, 1], ref cr);
                              break;
                          }
                      }
              }
          }
      }
      */

      static void otaczanie(ref Bitmap org, ref Bitmap tmp, int x, int y, ref int[,] cr)
      {
          int ilosc_czarnych_sasiadow = 0;


          for (int k = 0; k < 8; k++)
          {
              string t4 = tmp.GetPixel(x + cr[k, 0], y + cr[k, 1]).Name;
              if (t4 == "ff000000" || t4 == "ff040404")
                  ilosc_czarnych_sasiadow++;
          }

          if(ilosc_czarnych_sasiadow > 0)
              for (int k = 0; k < 8; k++)
              {
                  string t5 = tmp.GetPixel(x + cr[k, 0], y + cr[k, 1]).Name;
                  if (t5 == "ffffffff" || t5 == "fffcfcfc")
                  {
                      tmp.SetPixel(x + cr[k, 0], y + cr[k, 1], Color.Green);
                      otaczanie(ref org, ref tmp, x + cr[k, 0], y + cr[k, 1], ref cr);                    
                  }                
              }
      }

      public static double[] RatiosRCH(Bitmap test)
      {
          //R30 - 799 - 537
          int count_black = 0;          // czarny
          //int count_white = 0;          // bialy
          int perimeter = 0;        // obwod obiektu
          bool first = true;        // semafor czy znaleziono juz 1. pix obiektu
          int fx = 0, fy = 0;       // wsp. pierwszego pix czarnego -> poczatek obiektu
          int px = 0, py = 0;       // wsp. ostatnio znalezionego 

          double[] ratio_out = { 0, 0, 0, 0 }; // poszukiwane wsp. cyr.

          /*
          int[,] neigh4 = {                 { -1, 0 }, 
                                { 0, -1 },             { 0, 1 }, 
                                            { 1, 0 } };
          */

          // pomocnicza tabela ulatwiajaca iterowanie po sasiadach punktu
          int[,] neigh8 = {     { -1, -1 }, { -1, 0 }, { -1, 1 }, 
                                { 0, -1 },             { 0, 1 }, 
                                { 1, -1 },  { 1, 0 },  { 1, 1 } };

          itest = new Bitmap(test.Width, test.Height);

    // ++wsp. cyrkularnosc
          // szukanie po calym obrazie
          for (int i = 0; i < test.Width; i++)
              for (int j = 0; j < test.Height; j++)
              {
                  // jesli znaleziono pix. nalezacy do obiektu
                  string tttt = test.GetPixel(16, 29).Name;
                  string tt = test.GetPixel(i, j).Name;
                  if ( tt == "ff000000" || tt == "ff040404")
                  {
                      if (first)
                      { // szukanie pierwszego czarnego pixela
                          itest.SetPixel(i, j, Color.Black);
                          first = false;
                          fx = i; fy = j;   // zapamietanie wsp. 1. czarnego
                          px = i; py = j;   // zap. wsp poprzedniego czarnego (krawedz)(1.)
                      }

                      for (int k = 0; k < 8; k++)
                      {   // iterowanie po sasiadach czarnego
                          string t6 = test.GetPixel(i + neigh8[k, 0], j + neigh8[k, 1]).Name;
                          if ( t6 == "ffffffff" || t6 == "fffcfcfc")
                          { // jesli ma jakiegos sasiada bialego -> krawedz
                              // znajduje rowniez krawedzi wewnetrzne
                              itest.SetPixel(i, j, Color.Black);
                              break;
                          }
                      }

                      count_black++;    // liczenie pola powierzchni obiektu
                  }
              }

          ratio_out[rc1] = 2 * Math.Sqrt(count_black / Math.PI);

          // wyszukanie wlasciwego konturu, na kopii obrazu - itest zaznacza na czerwono
          // tylko zewnetrzna krawedz
          //oblewanie(ref test, ref itest, fx, fy, ref neigh8);

          itest2 = new Bitmap(test);
          otaczanie(ref test, ref itest2, fx, fy, ref neigh8);          

          for (int i = 0; i < itest2.Width; i++)
              for (int j = 0; j < itest2.Height; j++)
              {
                  // jesli znaleziono pix. nalezacy do obiektu
                  string t3 = itest2.GetPixel(i, j).Name;
                  if (t3 == "ff000000" || t3 == "ff040404")
                  {
                      for (int k = 0; k < 8; k++)
                      {   // iterowanie po sasiadach czarnego
                          if (itest2.GetPixel(i + neigh8[k, 0], j + neigh8[k, 1]).Name == "ff008000")
                          { // jesli ma jakiegos sasiada bialego -> krawedz
                              // znajduje rowniez krawedzi wewnetrzne
                              itest.SetPixel(i, j, Color.Red);
                              break;
                          }
                      }
                  }
              }         

          for (int i = 0; i < itest.Width; i++)
              for (int j = 0; j < itest.Height; j++)                  
                  if (itest.GetPixel(i, j).Name == "ffff0000")
                  // szukanie pix. w kolorze czerwonym - liczenie obwodu obiektu
                      perimeter++;

          ratio_out[rc2] = perimeter / Math.PI;
          ratio_out[rc12] = ratio_out[rc1] / ratio_out[rc2];
    // --wsp. cyrkularnosc

    // ++wsp. Haralicka
          //http://www.uwm.edu.pl/kipr/ksztalt.pdf
          int scx = 0, scy = 0; // wspolrzedne srodka ciezkosci
          int ile = 0;
          double odl = 0;       // suma odleglosci od srodka ciezkosci
          double odl2 = 0;      // suma kwadratow odleglosci od srodka ciezkosci
          double temd = 0;

          for (int i = 0; i < itest.Width; i++)
              for (int j = 0; j < itest.Height; j++)
                  if (itest.GetPixel(i, j).Name == "ffff0000")
                  { // na kopii obrazu szuka pix. czerwonych, bedacych konturem
                      // szuka srodka ciezkosci
                      scx += i;
                      scy += j;
                      ile++;        // ilosc pix. w konturze
                  }

          // srodek ciezkosci - x, y
          scx = (int)scx / ile;
          scy = (int)scy / ile;

          //itest.SetPixel(scx, scy, Color.Blue);

          for (int i = 0; i < itest.Width; i++)
              for (int j = 0; j < itest.Height; j++)
                  if (itest.GetPixel(i, j).Name == "ffff0000")
                  { // obliczanie odleglosci punktow konturu od srodka ciezkosci
                      temd = Math.Pow(Math.Abs(scx - i), 2) + Math.Pow(Math.Abs(scy - j), 2);
                      odl += Math.Sqrt(temd);
                      odl2 += (temd - 1); // zakladam, ze ta '1' jest tutaj
                  }

          ratio_out[rhar] = Math.Sqrt((odl * odl) / (ile * odl2));
    // --wsp. Haralicka

          return ratio_out;
      }


  }
}
